﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Reflection;
using Base;
using Components;
using System.Data.Objects.DataClasses;
using ERP.BusinessEntities.Base;
using Core.Component;
using ERP.DAL;
using ERP.BusinessEntities.Factory;
using ERP.BusinessEntities.Util;
using ERP.BusinessEntities;
using System.Transactions;
using System.Data;
using System.Collections;

namespace Core.Base
{
    public enum ActionType
    {
        None = 0,
        New = 1,
        Edit = 2,
    }

    public enum CalcLevel
    {
        None = -5,
        FK_GECurrencyID  = -5,
        FK_ICProducts_ID = -4,
        FK_ICStockUOMs_ID = -3,
        UOMRate = -2,
        FQty = -1,
        Qty = 0,
        ExcRate = 1,
        FUnitPrice = 2,
        UnitPrice = 3,
        FPrice = 4,
        Price = 5,
        FDiscAmt =6,
        DiscAmt = 7,
        FNetAmt = 8,
        NetAmt = 9,
        FK_TxTaxCodes_ID = 10,
        TaxPct = 11,
        FTaxAmt = 12,
        TaxAmt = 13,
        FAmt = 14,
        Amt = 15,
        FK_ICStocks_ID = 16
    }

    public enum OperationType
    {
        Sale = 0,
        Purchase = 1
    }

    public delegate void ActionStartHandler(Object sender, EventArgs e);

    public class BaseModule
    {
        public event ActionStartHandler ActionStart;

        private ActionType _action;

        public ActionType Action
        {
            get { return _action; }
            set 
            { 
                _action = value;
                if (_action == ActionType.None)
                {
                    FocustTo(null);
                    
                }
                if (ActionStart != null)
                    ActionStart(this, new EventArgs());

                foreach (KeyValuePair<String, ISGVList> pair in entity.dicLists)
                {
                    DataGridView gridView = pair.Value.GetGridView();
                    if (gridView != null)
                    {
                        if (_action == ActionType.None)
                            gridView.AllowUserToAddRows = false;
                        else
                            gridView.AllowUserToAddRows = true;
                    }
                }
            }
        }


        public String Name;

        public BaseEntity entity;

        public Form MainAppForm;
        public SGVSearchScreen SearchScreen;

        public Control FirstControl;

        public SGVGridView ItemGridView;

        public Form scrStartScreen;
        public Dictionary<String, Form> dicScreens = new Dictionary<string, Form>();
        //key = Module Name = TableName, Value = (FormName_ControlName, control)
        public Dictionary<String, Dictionary<String, Control>> dicModuleControls = new Dictionary<string, Dictionary<string, Control>>();
        public Dictionary<String, Control> dicControls = new Dictionary<string, Control>();

        public virtual void Init()
        {
            entity.module = this;
            entity.Init();
            InitAllScreens();
            entity.InitLists();
            UpdateBinding();
            Action = ActionType.None;
            LoadData();
        }

        public virtual void LoadData()
        {
        }

        public virtual void Open(Form AppContainer)
        {
            if (scrStartScreen == null) return;

            this.MainAppForm = AppContainer;

            scrStartScreen.MdiParent = this.MainAppForm;
//            scrMain.Text = "Window " + childFormNumber++;
            scrStartScreen.Show();
        }

        public void InitAllScreens()
        {
            Assembly[] assems = AppDomain.CurrentDomain.GetAssemblies();
            Type thisType = this.GetType();

            String strModulePrefix = thisType.Name.Substring(0, thisType.Name.Length - 6);

            foreach (Assembly ass in assems)
            {
                Type[] types = ass.GetTypes();

                foreach (Type t in types)
                {
                    //if (t.Namespace == null) continue;
                    if (t.FullName.Contains(String.Format(@".{0}.", strModulePrefix)) == false) continue;
                    //if (t.Namespace.ToString().Equals(thisType.Namespace.ToString()))
                    //    continue;

                    if (t.IsSubclassOf(typeof(SGVScreen)))
                    {
                        if (dicScreens.ContainsKey(t.Name)) continue;
                        SGVScreen frm = (SGVScreen)Activator.CreateInstance(t);
                        dicScreens.Add(t.Name, frm);
                        if (frm.Tag != null && frm.Tag.ToString().ToUpper().Equals(AppContext.strScreenStartTag))
                            scrStartScreen = frm;

                        frm.Init();
                        frm.RegisterModule(this);

                        try
                        {
                            GetControlInParent(frm.Name, frm);
                        }
                        catch (Exception ex)
                        {
                            
                        }
                        
                    }
                }
            }


        }

        public void GetControlInParent(String FormName, Control control)
        {
            if (control == null) return;

            foreach (Control ChildControl in control.Controls)
            {
                try
                {
                    String strControlKey = SGVControlHelper.GetControlKeyName(FormName, ChildControl.Name);
                    if (dicControls.ContainsKey(strControlKey) == false)
                    {
                        dicControls.Add(strControlKey, ChildControl);
                    }
                    if (ChildControl is IBindingControl)
                    {
                        IBindingControl bindingControl = (IBindingControl)ChildControl;
                        AppContext.InitControlFormat(bindingControl);

                        if (String.IsNullOrEmpty(bindingControl.BindingTable) && String.IsNullOrEmpty(bindingControl.BindingColumn) == false)
                            bindingControl.BindingTable = entity.strMainTable;
                        if (String.IsNullOrEmpty(bindingControl.BindingTable))
                            bindingControl.BindingTable = String.Empty;

                        if (entity.dicModuleObjects.ContainsKey(bindingControl.BindingTable))
                        {
                            if (dicModuleControls.ContainsKey(bindingControl.BindingTable) == false)
                                dicModuleControls.Add(bindingControl.BindingTable, new Dictionary<string, Control>());

                            if (dicModuleControls[bindingControl.BindingTable].ContainsKey(strControlKey) == false)
                                dicModuleControls[bindingControl.BindingTable].Add(strControlKey, ChildControl);
                        }
                    }

                    if (ChildControl is ISGVControl)
                    {
                        ISGVControl sgvControl = (ISGVControl)ChildControl;
                        if (String.IsNullOrEmpty(sgvControl.SGVTag) == false
                            && sgvControl.SGVTag.ToUpper() == AppContext.cstFirstControlTag)
                            FirstControl = ChildControl;

                        sgvControl.RegisterModule(this);
                        sgvControl.Init();
                        


                    }

                    GetControlInParent(FormName, ChildControl);
                }
                catch (Exception ex)
                {
                    
                }
                

                
            }
        }

        public void InvalidateMainObject(int iMainObjID)
        {
            if (iMainObjID <= 0)
                ActionNone();

            if (String.IsNullOrEmpty(entity.strMainTable) || entity.MainCtrl == null)
                ActionNone();

            entity.MainObject = (BaseBusinessInfo)entity.MainCtrl.GetObjectById(iMainObjID);

            UpdateBinding();
        }

        public void UpdateBinding()
        {
            foreach (KeyValuePair<String, BaseBusinessInfo> pair in entity.dicModuleObjects)
            {
                UpdateBinding(pair.Key);
            }
        }

        public void UpdateBinding(String strModuleName)
        {
            if (entity == null) return;

            if (dicModuleControls.ContainsKey(strModuleName) == false) return;
            if (entity.dicModuleObjects.ContainsKey(strModuleName) == false) return;

            Object obj = entity.dicModuleObjects[strModuleName];

            foreach (KeyValuePair<String, Control> pair in dicModuleControls[strModuleName])
            {
                if (pair.Value is IBindingControl)
                {

                    IBindingControl bindingControl = (IBindingControl)pair.Value;
                    if (String.IsNullOrEmpty(bindingControl.BindingPropertyName) == false && String.IsNullOrEmpty(bindingControl.BindingColumn) == false)
                    {
                        if (pair.Value is Components.SGVPictureBox)
                        {
                        }
                        InitBindingControl(pair.Value, obj, bindingControl.BindingPropertyName, bindingControl.BindingColumn);
                        
                    }
                }
                //if (pair.Value is ISGVControl)
                //{
                //    ((ISGVControl)pair.Value).UpdateFormat();
                //}
                

            }

        }

        public void InitBindingControl(Control control, Object obj, String strControlPropertyName, String strObjectPropertyName)
        {
            try
            {
                control.DataBindings.Clear();
                control.DataBindings.Add(new System.Windows.Forms.Binding(strControlPropertyName, obj, strObjectPropertyName, true, DataSourceUpdateMode.OnPropertyChanged));
            }
            catch (Exception ex)
            {
            }
           
        }

        public void FocustTo(Control control)
        {
            if (scrStartScreen != null && scrStartScreen is SGVMainScreen)
            {
                if (control != null)
                    scrStartScreen.ActiveControl = FirstControl;
                else
                    scrStartScreen.ActiveControl = ((SGVMainScreen)scrStartScreen).sgvToolbar1;
            }
        }

        #region Action

        public virtual void ActionNew()
        {
            Action = ActionType.New;
            entity.MainObject = (BaseBusinessInfo)BusinessFactory.CreateBusinessObject(entity.strMainTable + "Info");
            SetInitObject(entity.MainObject);

            UpdateBinding();

            FocustTo(FirstControl);

        }

        public virtual void ActionEdit()
        {
            if (entity.MainObject == null || entity.iMainObjectID <= 0)
            {
                MessageBox.Show("Please choose a Object to edit", "Can not Edit", MessageBoxButtons.OK, MessageBoxIcon.Information);
                return;
            }

            if (AppContext.CheckLock(entity.strMainTable, entity.iMainObjectID) == true)
            {
                MessageBox.Show("Đối tượng đang được giữ bởi người dùng khác, không thể Edit", "Cannot Edit", MessageBoxButtons.OK, MessageBoxIcon.Information);
                return;
            }

            AppContext.CreateLock(AppContext.CurrentUserInfo.No, entity.strMainTable, entity.iMainObjectID);

            Action = ActionType.Edit;
            entity.ReloadMainObject(entity.MainObject);
            UpdateBinding();

            FocustTo(FirstControl);

        }

        public virtual void ActionCancel()
        {
            AppContext.ReleaseLock(AppContext.CurrentUserInfo.No, entity.strMainTable, entity.iMainObjectID);
            Action = ActionType.None;
            entity.ReloadMainObject(entity._oldMainObject);
            UpdateBinding();
        }

        public virtual void ActionNone()
        {
            Action = ActionType.None;
            entity.MainObject = (BaseBusinessInfo)BusinessFactory.CreateBusinessObject(entity.strMainTable + "Info");

            UpdateBinding(entity.strMainTable);
        }

        public virtual void ActionDelete()
        {
            if (entity.MainObject == null || entity.iMainObjectID <= 0)
            {
                MessageBox.Show("Please choose a Object to edit", "Can not Edit", MessageBoxButtons.OK, MessageBoxIcon.Information);
                return;
            }

            DialogResult dlgResult = MessageBox.Show("Are you sure to delete this Object?", "Confirm", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
            if (dlgResult.Equals(DialogResult.Yes) == false)
                return;

            entity.ActionDelete();

            Action = ActionType.None;
        }

        public virtual void ActionSave()
        {
            using (TransactionScope tranScope = new TransactionScope(TransactionScopeOption.RequiresNew, new TimeSpan(1, 10, 30)))
            {
                try
                {
                    Object objNo = AppContext.GetProperty(entity.MainObject, AppContext.cstNo);
                    if (objNo != null)
                    {
                        String strNo = Convert.ToString(objNo);
                        if (String.IsNullOrEmpty(strNo) || strNo.Equals(AppContext.cstEmptyNo))
                        {
                            String strGenerateNo = AppContext.GenerateNo(this.Name, AppContext.GetServerDate());
                            AppContext.SetProperty(entity.MainObject, AppContext.cstNo, strGenerateNo);
                        }
                    }

                    entity.ActionSave(Action);
                    Action = ActionType.None;
                    AppContext.ReleaseLock(AppContext.CurrentUserInfo.No, entity.strMainTable, entity.iMainObjectID);
                    tranScope.Complete();
                    
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Có lỗi xảy ra khi lưu chứng từ, vui lòng kiểm tra lại");
                    tranScope.Dispose();
                }
                
            }
            
        }

        public virtual void ActionPrint()
        {
        }

        public virtual void List()
        {
            int iMainObjID = AppContext.ShowSearchScreen(this, entity.strMainTable, null, "No|Name|Dsc", String.Empty);
            InvalidateMainObject(iMainObjID);
        }

        public virtual void History()
        {
        }

        public virtual void Close()
        {
            foreach (KeyValuePair<String, Form> pair in dicScreens)
            {
                try
                {
                    pair.Value.Close();
                }
                catch (Exception)
                {
                }
            }
        }

        public virtual void Import()
        {

        }

        public virtual void Next()
        {
            String strQuery = String.Format(@"SELECT TOP(1) * FROM {0}
                                                WHERE AAStatus = 'Alive'
                                                AND ID > {1} ORDER BY ID", entity.strMainTable, entity.iMainObjectID);
            DataSet ds = entity.MainCtrl.GetDataset(strQuery);
            if (ds == null || ds.Tables.Count == 0 || ds.Tables[0].Rows.Count == 0)
            {
                strQuery = String.Format(@"SELECT TOP(1) * FROM {0}
                                                WHERE AAStatus = 'Alive'
                                                AND ID <> {1} ORDER BY ID", entity.strMainTable, entity.iMainObjectID);

                ds = entity.MainCtrl.GetDataset(strQuery);
            }

            if (ds != null && ds.Tables.Count > 0 && ds.Tables[0].Rows.Count > 0)
                entity.MainObject = (BaseBusinessInfo)entity.MainCtrl.GetObjectFromDataRow(ds.Tables[0].Rows[0]);

            UpdateBinding();
        }

        public virtual void Pre()
        {
            String strQuery = String.Format(@"SELECT TOP(1) * FROM {0}
                                                WHERE AAStatus = 'Alive'
                                                AND ID < {1} ORDER BY ID DESC", entity.strMainTable, entity.iMainObjectID);
            DataSet ds = entity.MainCtrl.GetDataset(strQuery);
            if (ds == null || ds.Tables.Count == 0 || ds.Tables[0].Rows.Count == 0)
            {
                strQuery = String.Format(@"SELECT TOP(1) * FROM {0}
                                                WHERE AAStatus = 'Alive'
                                                AND ID <> {1} ORDER BY ID DESC", entity.strMainTable, entity.iMainObjectID);

                ds = entity.MainCtrl.GetDataset(strQuery);
            }

            if (ds != null && ds.Tables.Count > 0 && ds.Tables[0].Rows.Count > 0)
                entity.MainObject = (BaseBusinessInfo)entity.MainCtrl.GetObjectFromDataRow(ds.Tables[0].Rows[0]);

            UpdateBinding();
        }

        #endregion

        #region Calculate

        public virtual void CalcObject(Object MainObj, String strFieldName)
        {
            if (AppContext.CheckEnumContain(typeof(CalcLevel), strFieldName) == false) return;
            CalcLevel level = (CalcLevel)Enum.Parse(typeof(CalcLevel), strFieldName);
            CalcObject(MainObj, level);
        }

        public virtual void CalcObject(Object MainObj, CalcLevel level)
        {
            IList lstItems = null;
            if (ItemGridView == null || ItemGridView.DataSource == null || ItemGridView.DataSource is IList == false)
                return;

            lstItems = (IList)ItemGridView.DataSource;
            if (lstItems == null) return;
            

            #region Declare Variable
            int iProductID = 0;
            int iStockID = 0;
            int iStockUOMID = 0;
            int iTaxCodeID = 0;
            double dUOMRate = 1.0;
            double dFQty = 1.0;
            double dQty = 1.0;
            double dUnitPrice = 0;
            double dFPrice = 0;
            double dPrice = 0;
            double dFDiscAmt = 0;
            double dDiscAmt = 0;
            double dFNetAmt = 0;
            double dNetAmt = 0;
            double dTaxPct = 0;
            double dFTaxAmt = 0;
            double dTaxAmt = 0;
            double dFAmt = 0;
            double dAmt = 0;
            #endregion

            //if (AppContext.CheckEnumContain(typeof(CalcLevel), strFieldName) == false) return;
            //CalcLevel level = (CalcLevel)Enum.Parse(typeof(CalcLevel), strFieldName);

            //Get CurrencyID
            int iCurrencyID = 1;
            Object objCurrencyID = AppContext.GetProperty(MainObj, AppContext.cstFK_Currency);
            if (objCurrencyID != null)
                iCurrencyID = Convert.ToInt32(objCurrencyID);

            //get Decimal Round
            int iDecimalRound = 2;
            GECurrencysInfo Currency = (GECurrencysInfo)AppContext.CurrencyCtrl.GetObjectById(iCurrencyID);
            if (Currency != null)
                iDecimalRound = Currency.DecimalRound;

            int iDefaultDecimalRound = 2;
            GECurrencysInfo DefaultCurrency = (GECurrencysInfo)AppContext.CurrencyCtrl.GetObjectById(AppContext.CurrentCompanyInfo.FK_GECurrencys_ID);
            if (DefaultCurrency != null)
                iDefaultDecimalRound = DefaultCurrency.DecimalRound;

            #region ItemFPrice
            if (level <= CalcLevel.FPrice)
            {
                double dItemFPrice = 0;
                foreach (Object objItem in lstItems)
                {
                    Object objFPrice = AppContext.GetProperty(objItem, AppContext.cstFPrice);
                    if (objFPrice != null)
                    {
                        dItemFPrice += Convert.ToDouble(objFPrice);
                    }
                }

                AppContext.SetProperty(MainObj, AppContext.cstMainItemPrefix + AppContext.cstFPrice, dItemFPrice);
            } 
            #endregion

            #region ItemPrice
            if (level <= CalcLevel.Price)
            {
                double dItemPrice = 0;
                foreach (Object objItem in lstItems)
                {
                    Object objPrice = AppContext.GetProperty(objItem, AppContext.cstPrice);
                    if (objPrice != null)
                    {
                        dItemPrice += Convert.ToDouble(objPrice);
                    }
                }

                AppContext.SetProperty(MainObj, AppContext.cstMainItemPrefix + AppContext.cstPrice, dItemPrice);
            }
            #endregion

            #region ItemFDiscAmt
            if (level <= CalcLevel.FDiscAmt)
            {
                double dItemFDiscAmt = 0;
                foreach (Object objItem in lstItems)
                {
                    Object objFDiscAmt = AppContext.GetProperty(objItem, AppContext.cstFDiscAmt);
                    if (objFDiscAmt != null)
                    {
                        dItemFDiscAmt += Convert.ToDouble(objFDiscAmt);
                    }
                }

                AppContext.SetProperty(MainObj, AppContext.cstMainItemPrefix + AppContext.cstFDiscAmt, dItemFDiscAmt);
            }
            #endregion

            #region ItemDiscAmt
            if (level <= CalcLevel.DiscAmt)
            {
                double dItemDiscAmt = 0;
                foreach (Object objItem in lstItems)
                {
                    Object objDiscAmt = AppContext.GetProperty(objItem, AppContext.cstDiscAmt);
                    if (objDiscAmt != null)
                    {
                        dItemDiscAmt += Convert.ToDouble(objDiscAmt);
                    }
                }

                AppContext.SetProperty(MainObj, AppContext.cstMainItemPrefix + AppContext.cstDiscAmt, dItemDiscAmt);
            }
            #endregion

            #region ItemFTaxAmt
            if (level <= CalcLevel.FTaxAmt)
            {
                double dItemFTaxAmt = 0;
                foreach (Object objItem in lstItems)
                {
                    Object objFTaxAmt = AppContext.GetProperty(objItem, AppContext.cstFTaxAmt);
                    if (objFTaxAmt != null)
                    {
                        dItemFTaxAmt += Convert.ToDouble(objFTaxAmt);
                    }
                }

                AppContext.SetProperty(MainObj, AppContext.cstMainItemPrefix + AppContext.cstFTaxAmt, dItemFTaxAmt);
            }
            #endregion

            #region ItemTaxAmt
            if (level <= CalcLevel.TaxAmt)
            {
                double dItemTaxAmt = 0;
                foreach (Object objItem in lstItems)
                {
                    Object objTaxAmt = AppContext.GetProperty(objItem, AppContext.cstTaxAmt);
                    if (objTaxAmt != null)
                    {
                        dItemTaxAmt += Convert.ToDouble(objTaxAmt);
                    }
                }

                AppContext.SetProperty(MainObj, AppContext.cstMainItemPrefix + AppContext.cstTaxAmt, dItemTaxAmt);
            }
            #endregion

            #region ItemFNetAmt
            if (level <= CalcLevel.FNetAmt)
            {
                double dItemFNetAmt = 0;
                foreach (Object objItem in lstItems)
                {
                    Object objFNetAmt = AppContext.GetProperty(objItem, AppContext.cstFNetAmt);
                    if (objFNetAmt != null)
                    {
                        dItemFNetAmt += Convert.ToDouble(objFNetAmt);
                    }
                }

                AppContext.SetProperty(MainObj, AppContext.cstMainItemPrefix + AppContext.cstFNetAmt, dItemFNetAmt);
            }
            #endregion

            #region ItemNetAmt
            if (level <= CalcLevel.NetAmt)
            {
                double dItemNetAmt = 0;
                foreach (Object objItem in lstItems)
                {
                    Object objNetAmt = AppContext.GetProperty(objItem, AppContext.cstNetAmt);
                    if (objNetAmt != null)
                    {
                        dItemNetAmt += Convert.ToDouble(objNetAmt);
                    }
                }

                AppContext.SetProperty(MainObj, AppContext.cstMainItemPrefix + AppContext.cstNetAmt, dItemNetAmt);
            }
            #endregion

            #region ItemFAmt
            if (level <= CalcLevel.FAmt)
            {
                double dItemFAmt = 0;
                foreach (Object objItem in lstItems)
                {
                    Object objFAmt = AppContext.GetProperty(objItem, AppContext.cstFAmt);
                    if (objFAmt != null)
                    {
                        dItemFAmt += Convert.ToDouble(objFAmt);
                    }
                }

                AppContext.SetProperty(MainObj, AppContext.cstMainItemPrefix + AppContext.cstFAmt, dItemFAmt);
                AppContext.SetProperty(MainObj, AppContext.cstFAmt, dItemFAmt);
            }
            #endregion

            #region ItemAmt
            if (level <= CalcLevel.Amt)
            {
                double dItemAmt = 0;
                foreach (Object objItem in lstItems)
                {
                    Object objAmt = AppContext.GetProperty(objItem, AppContext.cstAmt);
                    if (objAmt != null)
                    {
                        dItemAmt += Convert.ToDouble(objAmt);
                    }
                }

                AppContext.SetProperty(MainObj, AppContext.cstMainItemPrefix + AppContext.cstAmt, dItemAmt);
                AppContext.SetProperty(MainObj, AppContext.cstAmt, dItemAmt);
            }
            #endregion


            UpdateBinding(entity.strMainTable);
        }

        public virtual void CalcItem(Object MainObj, Object objItem, String strFieldName)
        {
            #region Declare Variable
            int iProductID = 0;
            int iStockID = 0;
            int iStockUOMID = 0;
            int iTaxCodeID = 0;
            double dUOMRate = 1.0;
            double dFQty = 1.0;
            double dQty = 1.0;
            double dFUnitPrice = 1.0;
            double dUnitPrice = 0;
            double dFPrice = 0;
            double dPrice = 0;
            double dFDiscAmt = 0;
            double dDiscAmt = 0;
            double dFNetAmt = 0;
            double dNetAmt = 0;
            double dTaxPct = 0;
            double dFTaxAmt = 0;
            double dTaxAmt = 0;
            double dFAmt = 0;
            double dAmt = 0;
            #endregion

            if (AppContext.CheckEnumContain(typeof(CalcLevel), strFieldName) == false) return;
            CalcLevel level = (CalcLevel)Enum.Parse(typeof(CalcLevel), strFieldName);
            
            //Get CurrencyID
            int iCurrencyID = 1;
            Object objCurrencyID = AppContext.GetProperty(MainObj, AppContext.cstFK_Currency);
            if (objCurrencyID != null)
                iCurrencyID = Convert.ToInt32(objCurrencyID);

            //get Decimal Round
            int iDecimalRound = 2;
            GECurrencysInfo Currency = (GECurrencysInfo)AppContext.CurrencyCtrl.GetObjectById(iCurrencyID);
            if (Currency != null)
                iDecimalRound = Currency.DecimalRound;

            int iDefaultDecimalRound = 2;
            GECurrencysInfo DefaultCurrency = (GECurrencysInfo)AppContext.CurrencyCtrl.GetObjectById(AppContext.CurrentCompanyInfo.FK_GECurrencys_ID);
            if (DefaultCurrency != null)
                iDefaultDecimalRound = DefaultCurrency.DecimalRound;

            //Get ExcRate
            double dExcRate = 1.0;
            Object objExcRate = AppContext.GetProperty(MainObj, AppContext.cstExcRate);
            if (objExcRate != null)
                dExcRate = Convert.ToDouble(objExcRate);

            ////Get FDiscAmt
            //Object objFDiscAmt = AppContext.GetProperty(objItem, AppContext.cstFDiscAmt);
            //if (objFDiscAmt != null)
            //    dFDiscAmt = Convert.ToDouble(objFDiscAmt);

            //Get ProductID
            Object objProductID = AppContext.GetProperty(objItem, AppContext.cstFKProduct);
            if (objProductID != null)
                iProductID = Convert.ToInt32(objProductID);
            ICProductsInfo Product = (ICProductsInfo)AppContext.ProductCtrl.GetObjectById(iProductID);

            #region FK_ICStockUOMs_ID
            //Calc FK_ICStockUOMs_ID
            if (level == CalcLevel.FK_ICProducts_ID)
            {
                CalcItem_FK_ICProducts_ID(objItem, Product);
            }
            #endregion

            #region FK_ICStockUOMs_ID
            //Calc FK_ICStockUOMs_ID
            if (level <= CalcLevel.FK_ICStockUOMs_ID)
            {
                Object objStockUOM = AppContext.GetProperty(objItem, "FK_ICStockUOMs_ID");
                if (objStockUOM != null)
                    iStockUOMID = Convert.ToInt32(objStockUOM);

                if (iStockUOMID == 0)
                {
                    CalcItem_FK_ICStockUOMs_ID(objItem, Product, ref iStockUOMID);
                    AppContext.SetProperty(objItem, AppContext.cstFKStockUOM, iStockUOMID);
                }
            } 
            #endregion

            #region UOM Rate
            //Calc UOMRate
            if (level < CalcLevel.UOMRate)
            {
                CalcItem_UOMRate(objItem, Product, ref dUOMRate);
                AppContext.SetProperty(objItem, AppContext.cstUOMRate, dUOMRate);
            } 
            #endregion

            #region FQty
            //Cacl FQty
            if (level < CalcLevel.FQty)
            {
                CalcItem_FQty(objItem, ref dFQty);
            } 
            #endregion

            #region Qty
            //Calc Qty
            if (level < CalcLevel.Qty)
            {
                CalcItem_Qty(objItem, ref dQty);
                AppContext.SetProperty(objItem, AppContext.cstQty, dQty);
            }
            #endregion

            #region FUnitPrice
            //Cacl FUnit Price
            if (level < CalcLevel.FUnitPrice)
                CalcItem_FUnitPrice(objItem, Product, ref dFUnitPrice);

            #endregion

            #region UnitPrice
            //Cacl Unit Price
            if (level < CalcLevel.UnitPrice)
                CalcItem_UnitPrice(objItem, iDefaultDecimalRound, dExcRate, ref dUnitPrice);
            #endregion

            #region FPrice
            if (level < CalcLevel.FPrice)
                CacItem_FPrice(objItem, iDecimalRound, ref dFPrice);
            #endregion

            #region Price
            if (level < CalcLevel.Price)
                CalcItem_Price(objItem, iDefaultDecimalRound, ref dPrice);
            #endregion

            #region DiscAmt
            if (level < CalcLevel.DiscAmt)
                CalcItem_DiscAmt(objItem, iDefaultDecimalRound, ref dDiscAmt);
            #endregion

            #region FNetAmt
            if (level < CalcLevel.FNetAmt)
                CalcItem_FNetAmt(objItem, iDecimalRound, ref dFNetAmt);
            
            #endregion

            #region NetAmt
            if (level < CalcLevel.NetAmt)
                CalcItem_NetAmt(objItem, iDefaultDecimalRound, dExcRate, ref dNetAmt);
            #endregion

            #region FK_TxTaxCodes_ID
            if (level < CalcLevel.FK_TxTaxCodes_ID)
                CalcItem_FK_TxTaxCodes_ID(objItem, Product,ref iTaxCodeID);
            #endregion

            #region TaxPct
            if (level < CalcLevel.TaxPct)
                CalcItem_TaxPct(objItem, ref dTaxPct);
            #endregion

            #region FTaxAmt
            if (level < CalcLevel.FTaxAmt)
                CalcItem_FTaxAmt(objItem, iDecimalRound, ref dFTaxAmt);
            #endregion

            #region TaxAmt
            if (level < CalcLevel.TaxAmt)
                CalcItem_TaxAmt(objItem, iDefaultDecimalRound, dExcRate,ref dTaxAmt);
            #endregion

            #region FAmt
            if (level < CalcLevel.FAmt)
                CalcItem_FAmt(objItem, iDecimalRound, ref dFAmt);
            #endregion

            #region Amt
            if (level < CalcLevel.Amt)
                CalcItem_Amt(objItem, iDefaultDecimalRound, dExcRate, ref dAmt);
            #endregion

            #region StockID
            //Calc FK_ICStocks_ID
            if (level < CalcLevel.FK_ICStocks_ID)
            {
                //Get StockID
                Object objStockID = AppContext.GetProperty(objItem, AppContext.cstFKStock);
                if (objStockID != null)
                    iStockID = Convert.ToInt32(objStockID);

                if (iStockID == 0)
                {
                    if (Product != null)
                        iStockID = Product.FK_ICStocks_ID;

                    AppContext.SetProperty(objItem, AppContext.cstFKStock, iStockID);
                }
            } 
            #endregion

            CalcObject(MainObj, level);
        }

        public virtual void CalcItem_FK_ICProducts_ID(Object objItem, ICProductsInfo Product)
        {
            AppContext.SetProperty(objItem, AppContext.cstFKStock, Product.FK_ICStocks_ID);
            AppContext.SetProperty(objItem, AppContext.cstFKStockUOM, Product.FK_ICStockUOMs_ID);
            AppContext.SetProperty(objItem, AppContext.cstFKTaxCode, Product.FK_TxTaxCodes_InVATID);
            AppContext.SetProperty(objItem, AppContext.cstFUnitPrice, Product.PurchaseUnitPrice);
        }

        public virtual void CalcItem_Amt(Object objItem, int iDefaultDecimalRound, double dExcRate, ref double dAmt)
        {
            double dFAmt = 0;
            Object objFAmt = AppContext.GetProperty(objItem, AppContext.cstFAmt);
            if (objFAmt != null)
                dFAmt = Convert.ToDouble(objFAmt);

            dAmt = Math.Round(dFAmt * dExcRate, iDefaultDecimalRound);
            AppContext.SetProperty(objItem, AppContext.cstAmt, dAmt);
        }

        public virtual void CalcItem_FAmt(Object objItem, int iDecimalRound, ref double dFAmt)
        {
            double dFNetAmt = 0;
            Object objFNetAmt = AppContext.GetProperty(objItem, AppContext.cstFNetAmt);
            if (objFNetAmt != null)
                dFNetAmt = Convert.ToDouble(objFNetAmt);

            double dFTaxAmt = 0;
            Object objFTaxAmt = AppContext.GetProperty(objItem, AppContext.cstFTaxAmt);
            if (objFTaxAmt != null)
                dFTaxAmt = Convert.ToDouble(objFTaxAmt);

            dFAmt = Math.Round(dFNetAmt + dFTaxAmt, iDecimalRound);
            AppContext.SetProperty(objItem, AppContext.cstFAmt, dFAmt);
        }

        public virtual void CalcItem_TaxAmt(Object objItem, int iDefaultDecimalRound, double dExcRate, ref double dTaxAmt)
        {
            double dFTaxAmt = 0;
            Object objFTaxAmt = AppContext.GetProperty(objItem, AppContext.cstFTaxAmt);
            if (objFTaxAmt != null)
                dFTaxAmt = Convert.ToDouble(objFTaxAmt);

            dTaxAmt = Math.Round(dFTaxAmt * dExcRate, iDefaultDecimalRound);
            AppContext.SetProperty(objItem, AppContext.cstTaxAmt, dTaxAmt);
        }

        public virtual void CalcItem_FTaxAmt(Object objItem, int iDecimalRound, ref double dFTaxAmt)
        {
            double dFNetAmt = 0;
            Object objFNetAmt = AppContext.GetProperty(objItem, AppContext.cstFNetAmt);
            if (objFNetAmt != null)
                dFNetAmt = Convert.ToDouble(objFNetAmt);

            double dTaxPct = 0;
            Object objTaxPct = AppContext.GetProperty(objItem, AppContext.cstTaxPct);
            if (objTaxPct != null)
                dTaxPct = Convert.ToDouble(objTaxPct);

            dFTaxAmt = Math.Round(dFNetAmt * dTaxPct / 100, iDecimalRound);
            AppContext.SetProperty(objItem, AppContext.cstFTaxAmt, dFTaxAmt);
        }

        public virtual void CalcItem_TaxPct(Object objItem, ref double dTaxPct)
        {
            int iTaxCodeID = 0;
            Object objTaxCode = AppContext.GetProperty(objItem, AppContext.cstFKTaxCode);
            if (objTaxCode != null)
                iTaxCodeID = Convert.ToInt32(objTaxCode);

            TxTaxCodesInfo TaxCode = (TxTaxCodesInfo)AppContext.TaxCodeCtrl.GetObjectById(iTaxCodeID);
            if (TaxCode != null)
                dTaxPct = TaxCode.TaxPct;
            else
                dTaxPct = 0;

            AppContext.SetProperty(objItem, AppContext.cstTaxPct, dTaxPct);
        }

        public virtual void CalcItem_FK_TxTaxCodes_ID(Object objItem, ICProductsInfo Product, ref int iTaxCodeID)
        {
            Object objTaxCode = AppContext.GetProperty(objItem, AppContext.cstFKTaxCode);
            if (objTaxCode != null)
                iTaxCodeID = Convert.ToInt32(objTaxCode);

            TxTaxCodesInfo TaxCode = (TxTaxCodesInfo)AppContext.TaxCodeCtrl.GetObjectById(iTaxCodeID);
            if (TaxCode == null && Product != null)
            {
                iTaxCodeID = Product.FK_TxTaxCodes_InVATID;
                AppContext.SetProperty(objItem, AppContext.cstFKTaxCode, iTaxCodeID);
            }
        }

        public virtual void CalcItem_NetAmt(Object objItem, int iDefaultDecimalRound, double dExcRate, ref double dNetAmt)
        {
            double dFNetAmt = 0;
            Object objFNetAmt = AppContext.GetProperty(objItem, AppContext.cstFNetAmt);
            if (objFNetAmt != null)
                dFNetAmt = Convert.ToDouble(objFNetAmt);

            dNetAmt = Math.Round(dFNetAmt * dExcRate, iDefaultDecimalRound);
            AppContext.SetProperty(objItem, AppContext.cstNetAmt, dNetAmt);
        }

        public virtual void CalcItem_FNetAmt(Object objItem, int iDecimalRound, ref double dFNetAmt)
        {
            double dFPrice = 0;
            Object objFPrice = AppContext.GetProperty(objItem, AppContext.cstFPrice);
            if (objFPrice != null)
                dFPrice = Convert.ToDouble(objFPrice);

            double dFDiscAmt = 0;
            Object objFDiscAmt = AppContext.GetProperty(objItem, AppContext.cstFDiscAmt);
            if (objFDiscAmt != null)
                dFDiscAmt = Convert.ToDouble(objFDiscAmt);

            dFNetAmt = Math.Round(dFPrice - dFDiscAmt, iDecimalRound);
            AppContext.SetProperty(objItem, AppContext.cstFNetAmt, dFNetAmt);
        }

        public virtual void CalcItem_DiscAmt(Object objItem, int iDefaultDecimalRound, ref double dDiscAmt)
        {
            double dFDiscAmt = 0;
            Object objFDiscAmt = AppContext.GetProperty(objItem, AppContext.cstFDiscAmt);
            if (objFDiscAmt != null)
                dFDiscAmt = Convert.ToDouble(objFDiscAmt);

            dDiscAmt = Math.Round(dFDiscAmt, iDefaultDecimalRound);
            AppContext.SetProperty(objItem, AppContext.cstDiscAmt, dDiscAmt);
        }

        public virtual void CalcItem_Price(Object objItem, int iDefaultDecimalRound, ref double dPrice)
        {
            double dUnitPrice = 0;
            Object objUnitPrice = AppContext.GetProperty(objItem, AppContext.cstUnitPrice);
            if (objUnitPrice != null)
                dUnitPrice = Convert.ToDouble(objUnitPrice);

            double dQty = 0;
            //Get UnitPrice
            Object objQty = AppContext.GetProperty(objItem, AppContext.cstQty);
            if (objQty != null)
                dQty = Convert.ToDouble(objQty);

            dPrice = Math.Round(dUnitPrice * dQty, iDefaultDecimalRound);
            AppContext.SetProperty(objItem, AppContext.cstPrice, dPrice);
        }

        public virtual void CacItem_FPrice(Object objItem, int iDecimalRound, ref double dFPrice)
        {
            double dFUnitPrice = 0;
            //Get UnitPrice
            Object objFUnitPrice = AppContext.GetProperty(objItem, AppContext.cstFUnitPrice);
            if (objFUnitPrice != null)
                dFUnitPrice = Convert.ToDouble(objFUnitPrice);

            double dQty = 0;
            //Get UnitPrice
            Object objQty = AppContext.GetProperty(objItem, AppContext.cstQty);
            if (objQty != null)
                dQty = Convert.ToDouble(objQty);

            dFPrice = Math.Round(dFUnitPrice * dQty, iDecimalRound);
            AppContext.SetProperty(objItem, AppContext.cstFPrice, dFPrice);
        }

        public virtual void CalcItem_UnitPrice(Object objItem, int iDefaultDecimalRound, double dExcRate, ref double dUnitPrice)
        {
            double dFUnitPrice = 0;
            //Get FUnitPrice
            Object objFUnitPrice = AppContext.GetProperty(objItem, AppContext.cstFUnitPrice);
            if (objFUnitPrice != null)
                dFUnitPrice = Convert.ToDouble(objFUnitPrice);

            dUnitPrice = Math.Round(dFUnitPrice * dExcRate, iDefaultDecimalRound);
            AppContext.SetProperty(objItem, AppContext.cstUnitPrice, dUnitPrice);
            
        }

        public virtual void CalcItem_FUnitPrice(Object objItem, ICProductsInfo Product, ref double dFUnitPrice)
        {
            //Get FUnitPrice
            Object objFUnitPrice = AppContext.GetProperty(objItem, AppContext.cstFUnitPrice);
            if (objFUnitPrice != null)
                dFUnitPrice = Convert.ToDouble(objFUnitPrice);

            if (dFUnitPrice == 0 && Product != null)
                dFUnitPrice = Product.PurchaseUnitPrice;

            AppContext.SetProperty(objItem, AppContext.cstFUnitPrice, dFUnitPrice);
        }

        public virtual void CalcItem_Qty(Object objItem, ref double dQty)
        {
            double dFQty = 0;
            double dUOMRate = 0;

            Object objUOMRate = AppContext.GetProperty(objItem, AppContext.cstUOMRate);
            if (objUOMRate != null)
                dUOMRate = Convert.ToDouble(objUOMRate);

            Object objFQty = AppContext.GetProperty(objItem, AppContext.cstFQty);
            if (objFQty != null)
                dFQty = Convert.ToDouble(objFQty);

            dQty = Math.Round(dFQty * dUOMRate, 0);
            if (dQty == 0) dQty = 1.0;
            
        }

        public virtual void CalcItem_FQty(Object objItem, ref double dFQty)
        {
            //Get FQty
            Object objFQty = AppContext.GetProperty(objItem, AppContext.cstFQty);
            if (objFQty != null)
                dFQty = Convert.ToDouble(objFQty);

            if (dFQty == 0)
            {
                dFQty = 1.0;
                AppContext.SetProperty(objItem, AppContext.cstFQty, dFQty);
            }
        }

        public virtual void CalcItem_FK_ICStockUOMs_ID(Object objItem, ICProductsInfo Product, ref int iStockUOMID)
        {
            if (Product != null)
                iStockUOMID = Product.FK_ICStockUOMs_ID;

            
        }

        public virtual void CalcItem_UOMRate(Object objItem, ICProductsInfo Product, ref double dUOMRate)
        {
            int iStockUOMID = 0;
            Object objUOMID = AppContext.GetProperty(objItem, AppContext.cstFKStockUOM);
            if (objUOMID != null)
                iStockUOMID = Convert.ToInt32(objUOMID);

            ICStockUOMsInfo StockUOM = (ICStockUOMsInfo)AppContext.StockUOMCtrl.GetObjectById(iStockUOMID);

            if (Product != null && StockUOM != null)
            {
                ICProductUOMsInfo ProductUOM = AppContext.ProductUOMCtrl.GetObject(Product.ID, StockUOM.ID);
                if (ProductUOM != null)
                    dUOMRate = ProductUOM.UOMRate;
            }
        }

        public virtual void InitDefaultItems(Object objItem)
        {
            //Get FQty
            double dFQty = 1.0;
            Object objFQty = AppContext.GetProperty(objItem, AppContext.cstFQty);
            if (objFQty != null)
                dFQty = Convert.ToDouble(objFQty);

            if (dFQty == 0)
                AppContext.SetProperty(objItem, AppContext.cstFQty, 1.0);
        }
        #endregion

        #region Validating
        public virtual String ObjectValidating(Object obj)
        {
            String strErrorText = String.Empty;

            return strErrorText;
        }

        public virtual String FieldValidating(Object obj, String strFieldName, Object NewValue)
        {
            String strErrorText = String.Empty;

            return strErrorText;
        }

        public virtual void ObjectValidated(Object obj)
        {
        }

        public virtual void FieldValidated(Object obj, String strFieldName, Object NewValue)
        {
        }

        #endregion

        public static void SetInitObject(Object obj)
        {
            try
            {
                AppContext.SetProperty(obj, "No", AppContext.cstEmptyNo);
                if (AppContext.GetProperty(obj, "FK_GECurrencys_ID") != null)
                    AppContext.SetProperty(obj, "FK_GECurrencys_ID", AppContext.CurrentCompanyInfo.FK_GECurrencys_ID);
                if (AppContext.GetProperty(obj, "ExcRate") != null)
                    AppContext.SetProperty(obj, "ExcRate", 1.0);
            }
            catch (Exception)
            {
            }
            

        }

    }
}
